<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body>
<h1>Registry Resolver &#8211; Pseudo Code and Notes</h1>
<p><em>Last updated April 15, 2003</em></p>
<pre>if (registry is already resolved)
   stop now &#8211; nothing to do

foreach (plugin in the registry) do {
   if (the plugin is missing any of the required fields)
      generate an error and disable this plugin
   make an IndexEntry for this plugin id (if one doesn&#8217;t exist)
   put this plugin in the version list of this IndexEntry in order from largest down
} end foreach

foreach (fragment in the registry) do {
   if (the fragment is missing any of the required fields)
      generate an error and ignore this fragment
   make sure all prerequisites for this fragment exist (bug 10799)
   find the plugin for fragment.getPluginId() + fragment.getPluginVersion() using 
      the matching rules described in class PluginVersionIdentifier (bug 5668)
   if (the plugin is not found)
      generate an error and ignore this fragment
   add this fragment to the plugin&#8217;s list of fragments (plugin.fragments)
} end foreach

foreach (plugin in the registry) do {
   foreach (fragment in this plugin&#8217;s fragment list) do {
      if (this is the most recent version of this fragment in this list)
         add the components of this fragment to this plugin
      if (this fragment adds a library to the plugin)
         make sure we don&#8217;t have duplicate library entries in the plugin (bug 23522)
   } end foreach
   remove any fragments not contributing to the plugin (i.e. older versions of a fragment) (bug 10719 and 10720)
} end foreach

identify all the root plugin ids
foreach (root plugin id) do {
   identify the latest version of the root and use it only
   build the ConstraintsEntry -&gt; Constraints structure under this IndexEntry  
   recursively build these structures for each prerequisite
} end foreach</pre>
<p>NOTE: When the above foreach is done, each plugin id will have an associated 
  IndexEntry -&gt; ConstraintsEntry -&gt; Constraints structure. For a given plugin 
  id, the associated IndexEntry, etc. will identify all plugins which require 
  this one as a prerequisite and all conditions which much be satisfied.
  The building of these structures must also remove any prerequisite loops and 
  remove any conflicts. This may require disabling some plugins and removing portions 
  of the ConstraintsEntry -&gt; Constraints structure under a particular IndexEntry.</p>
<pre>foreach (IndexEntry) do {
   foreach (ConstraintsEntry) do {
      find the plugin descriptor that is a best match for this group of Constraints
   } end foreach (ConstraintsEntry)
} end foreach (IndexEntry)


disable all plugin descriptors


foreach (IndexEntry) do {
   foreach (ConstraintsEntry) do {
      enable the plugin found to be the best match in the previous loop
      find the PluginPrerequisite that this plugin descriptor satisfies
      tell the PluginPrerequisite which version we resolved to
   } end foreach (ConstraintsEntry) 
} end foreach (IndexEntry)
	
optional &#8211; remove all disabled plugins from the registry
optional
foreach (enabled plugin in the registry) do {
   foreach (extension in this plugin) do {
      find the associated extension point
      if (extension point not found){
         generate an error
         NOTE: Should the plugin be disabled?
      } endif
      add this extension to the list of extensions for the found extension point
   } end foreach (extension) 
} end foreach (enabled plugin)
end optional
</pre>
<h3>Some Notes:</h3>
<p>A plugin with no extensions or extension points is termed a &#8216;library&#8217; 
  plugin.</p>
<p>Version Numbers are matched as follows:
<li>if no version number is specified, pick the latest version that satisfies any other related constraints</li>
<li>if only a version number is specified, ensure a &#8216;compatible&#8217; match</li>
<li>for exact matching rules, check out class PluginVersionIdentifier</li>
<li>multiple versions of a particular plugin id are allowed only if there are 
no extensions or extension points in any of the versions</li>
<li>we always try to use at most 1 version of a plugin even if all plugins are 
  &#8216;library&#8217; plugins.</li>
<p>Example (all plugins are library plugins):</p>
<li>pluginA version 1.2.0 requires pluginB and pluginC version 1.0.0</li>
<li>pluginB version 1.0.0 has no requirements</li>
<li>pluginB version 2.1.0 requires pluginC</li>
<li>pluginC version 1.0.0 has no requirements</li>
<li>pluginC version 1.1.0 has no requirements</li>
<li>pluginC version 2.0.5 has no requirements</li>
<p>Resolving will give us the following plugins:</p>
<li>pluginA version 1.2.0 requires pluginB and pluginC version 1.0.0</li>
<li>pluginB version 2.1.0 requires pluginC</li>
<li>pluginC version 1.1.0 has no requirements</li>
<p>Ideally, pluginB could have used pluginC version 2.0.5.</p>
<h3>Internal RegistryResolver structures:</h3>
<h4>IndexEntry:</h4>
<li>one index entry for each plugin id</li>
<li>each index entry has a pointer to each of the plugin descriptors that have this id</li>
<li>the pointers of plugin descriptors are in version order from the largest version to the smallest</li>
<li>each index entry also has a list of ConstraintsEntry&#8217;s (each ConstraintsEntry 
represents a group of constraints that can all be satisfied without conflict)</li>
<li>there is no ordering of ConstraintsEntry&#8217;s (just the order in which they are built)</li>
<h4>ConstraintsEntry:</h4>
<li>represents a group of constraints on a particular plugin id that can all be 
  satisfied without conflict</li>
<li>these constraints are kept in a list</li>
<li>a new ConstraintsEntry is not created if multiple versions of this plugin 
  are required and extensions or extension points exist</li>
<li>when an IndexEntry is created, the first (empty) ConstraintsEntry is also 
  created (therefore, the first invocation must use this first ConstrainsEntry 
  while other invocations may need to create a new one, if concurrent versions 
  of this plugin are allowed)</li>
<li>the ConstraintsEntry points back to it&#8217;s parent IndexEntry</li>
<h4>Constraint:</h4>
<li>represents a particular prerequisite in a plugin</li>
<li>a Constraint hangs off a ConstraintsEntry and a ConstraintsEntry hangs off 
  an IndexEntry. The &#8216;parent&#8217; plugin descriptor in the Constraint 
  is one of the same plugin descriptors that can be found in the version list 
  for this IndexEntry</li>
<li>each Constraint exists in only one ConstraintsEntry but a ConstraintsEntry 
  can have multiple Constraints</li>
<li>the Constraint points back to its parent ConstraintsEntry</li>
<h4>Cookie:</h4>
<li>used primarily as a tool to communicate any errors back to the calling methods 
  (and thus terminate processing of a particular area of the tree)</li>
<li>keeps a list of all Constraints that have been successfully evaluated to the 
  current point of execution. This list of constraints is also our was of ensure 
  we don&#8217;t have any circular dependencies. If we have already have a constraint 
  in this list with the same PluginPrerequisite as the one we are currently trying 
  to resolve, we know we have a circular dependency.</li>
<h4>Orphaned Subtrees:</h4>
<p>If a conflict arises such that a particular subtree becomes orphaned, the root 
  of this subtree will be considered a root node and the remainder of the subtree 
  (if it resolves correctly) will remain intact. Consider the following example 
  (pluginResolveTest_15):</p>
<p>PluginA 1.2.0 requires PluginB 2.1.0 and PluginC 1.0.0<br>
  PluginB 1.0.0 has no requirements but does have an extension and extension point<br>
  PluginB 2.1.0 requires PluginC 2.0.5 (exact match)<br>
  PluginC 1.0.0 has no requirements<br>
  PluginC 1.1.0 has no requirements but have an extension and extension point<br>
  PluginC 2.0.5 has no requirements</p>
<p>In this case, a conflict (non-resolvable because of extensions and extension 
  points) exists in PluginA and it is disabled. This causes PluginB to be orphaned 
  and it is then considered a root. Resolution of the above example will return 
  a registry containing PluginB 2.1.0 and PluginC 2.0.5. While this may seem counter-intuitive, 
  consider the case where PluginA was a PDE plugin and PluginB was the JDT plugin. 
  JDT can live without PDE and the subtree really should survive the conflict 
  in PDE&#8217;s plugin.</p>
<h4>Soft Prerequisites (Optional clause):</h4>
<p>We now have the notion of prerequisites which are optional, called soft prerequisites. 
  These prerequisites must have the clause &#8216;optional=&#8221;true&#8221;&#8217;. 
  Consider the following xml statement:</p>
<pre>&lt;requires&gt;
   &lt;import plugin=&quot;tests.c&quot; version=&quot;2.1.0&quot; optional=&#8221;true&#8221;/&gt;
&lt;/requires&gt;</pre>
<p>This prerequisite will be ignored if any of the following conditions apply:</p>
<li>the plugin &#8216;tests.c&#8217; does not exist at all</li>
<li>the plugin &#8216;tests.c&#8217; does exist but there are no versions compatible 
  with version number 2.1.0</li>
<li>the plugin &#8216;tests.c&#8217; exists and there is a version compatible 
  with 2.1.0 but the addition of this plugin will cause a conflict. A conflict 
  arises if a particular root plugin requires more than one version of &#8216;tests.c&#8217;, 
  the versions are not compatible with each other, and at least one of the versions 
  contains a minimum of one extension or extension point</li>
<p>If an optional prerequisite is ignored for any of the reasons listed above 
  no error message is generated (but an informational message may be output to 
  indicate that this prerequisite is being ignored). Ignoring an optional prerequisite 
  does not cause any plugins to be disabled. This causes potential error conditions 
  to be more complex. Each time we have a situation where we have a conflict, 
  we must first check to see if this is an optional prerequisite. The same is 
  true of situations where we expect to find an associated IndexEntry (or other 
  structure).</p>
<p>If a prerequisite is ignored, the Constraint structure associated with this 
  particular parent/prerequisite pair is not added into the IndexEntry, ConstraintsEntry, 
  Constraint structure. None of the existing structures or pointers to them are 
  altered or removed. We cannot tell, without re-examining every relationship 
  associated with this particular root plugin, which portions were used for other 
  relationships (and not just the relationship leading to this ignored prerequisite).</p>
<h4>Question on &#8216;lastResolved&#8217; field:</h4>
<p>The ConstraintsEntry structure contains a field called &#8216;lastResolved&#8217; 
  which is set but does not seem to be used. At the same time, there are numerous 
  places where we examine all of the Constraints off a ConstraintsEntry structure 
  to determine which plugin (if any) is the best one to resolve these Constraints 
  compatibly. Can we use &#8216;lastResolved&#8217; to try and minimize these? 
  Each time we look for a best match plugin, we cycle through all versions of 
  this plugin and all Constraints off this ConstraintsEntry.</p>
<p></p>
</body>
</html>
